﻿using MiniFox.Infrastructure.Attributes;
using System.Collections.Generic;
using System.Linq;
using System;
using System.Linq.Expressions;
using System.Reflection;

namespace MiniFox.Infrastructure
{
    /// <summary>
    /// 
    /// </summary>
    /// <typeparam name="D"></typeparam>
    public abstract class TreeResultObjectBase<D> : ResultObject<IEnumerable<ITreeNode>>, ITreeObject
    {
        string _nodeKey;
        string _superKey;
        string _sortKey;
        string _groupKey;
        /// <summary>
        /// 
        /// </summary>
        /// <param name="rowCount"></param>
        public TreeResultObjectBase(int rowCount) : base(rowCount)
        {
            var type = typeof(D);
            var attr = type.GetCustomAttribute<TreeNodeAttribute>();
            _nodeKey = attr.NodeKey;
            _superKey = attr.SuperKey;
            _sortKey = attr.SortKey;
            _groupKey = attr.GroupKey;
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="rowCount"></param>
        /// <param name="nodeKey"></param>
        /// <param name="superKey"></param>
        /// <param name="sortKey"></param>
        /// <param name="groupKey"></param>
        public TreeResultObjectBase(int rowCount, string nodeKey, string superKey, string sortKey, string groupKey) : base(rowCount)
        {
            _superKey = superKey;
            _nodeKey = nodeKey;
            _sortKey = sortKey;
            _groupKey = groupKey;
        }
        /// <summary>
        /// 
        /// </summary>
        public string NodeKey
        {
            get
            {
                return _nodeKey;
            }
        }
        /// <summary>
        /// 
        /// </summary>
        public string SuperKey
        {
            get
            {
                return _superKey;
            }
        }
        /// <summary>
        /// 
        /// </summary>
        public string GroupKey
        {
            get
            {
                return _groupKey;
            }
        }
        /// <summary>
        /// 
        /// </summary>
        public string SortKey
        {
            get
            {
                return _sortKey;
            }
        }
        /// <summary>
        /// 
        /// </summary>
        public override IEnumerable<ITreeNode> Result
        {
            get
            {
                return this.TreeGroups.Select(t => t.Tree);
            }
            set
            {
                throw new NotSupportedException();
            }
        }
        TreeGroupCollection _groups;
        /// <summary>
        /// 
        /// </summary>
        public virtual TreeGroupCollection TreeGroups
        {
            get
            {
                if (_groups == null)
                {
                    _groups = CreateTreeGroups();
                }
                return _groups;
            }
        }
        private TreeGroupCollection CreateTreeGroups()
        {
            var groups = GetGroups();
            TreeGroupCollection treeGroups = new TreeGroupCollection();
            foreach (var group in groups)
            {
                treeGroups.Add(CreateTreeGroup(group.Key, group.ToArray()));
            }
            return treeGroups;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="groupId"></param>
        /// <param name="groupFlatData"></param>
        /// <returns></returns>
        protected virtual ITreeGroup CreateTreeGroup(object groupId, IEnumerable<D> groupFlatData)
        {
            return new TreeGroup<D>(groupId, this.NodeKey, this.SuperKey, this.SortKey, groupFlatData);
        }
        /// <summary>
        /// 
        /// </summary>
        /// <returns></returns>
        protected abstract IEnumerable<IGrouping<object, D>> GetGroups();
    }
}
